﻿using System;
using System.Threading.Tasks;
using AutoFixture.Xunit2;
using Sustainalytics.Auth.Common;
using Sustainalytics.Auth.Service.GA;
using Sustainalytics.Auth.Service.Properties;
using Sustainalytics.Entities;
using Xunit;

namespace Sustainalytics.Auth.Service.Tests
{
    [Trait("Category", "Unit")]
    public class Get_token_with_password_should : IClassFixture<TokenServer>
    {
        private readonly TokenServer tokenServer;

        public Get_token_with_password_should(TokenServer tokenServer)
        {
            this.tokenServer = tokenServer;
        }

        [Fact]
        public async Task return_bad_request_when_client_id_is_not_sent()
        {
            var response = await tokenServer.GetReponseByPasswordAsync(clientId: null);

            response.ShouldBeErrorResponse(Resources.MissingClientId);
        }

        [Fact]
        public async Task return_bad_request_when_client_is_invalid()
        {
            var response = await tokenServer.GetReponseByPasswordAsync(clientId: "invalid client_id");

            response.ShouldBeErrorResponse(Resources.InvalidClientId);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_username_is_not_sent()
        {
            var response = await tokenServer.GetReponseByPasswordAsync();

            response.ShouldBeErrorResponse(Resources.WrongEmail, Resources.MissingUsername);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_password_is_not_sent(string username)
        {
            var response = await tokenServer.GetReponseByPasswordAsync(username);

            response.ShouldBeErrorResponse(Resources.InvalidCredentials, Resources.MissingPassword);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_user_is_not_found(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, null);

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeErrorResponse(Resources.WrongEmail, Resources.UserNotFound);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_user_is_not_active(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, new GaUser { Status = Status.Inactive });

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeErrorResponse(Resources.InactiveAccount, Resources.InactiveAccountMessage);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_password_is_expired(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, new GaUser { PasswordExpirationDate = DateTime.UtcNow.AddDays(-1) });

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeErrorResponse(Resources.ExpiredPassword, Resources.ExpiredPasswordMessage);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_password_is_incorrect(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, new GaUser
            {
                Username = username,
                Password = PasswordManager.HashPassword(password),
                PasswordExpirationDate = DateTime.UtcNow.AddDays(1),
            });

            var response = await tokenServer.GetReponseByPasswordAsync(username, "wrong password");

            response.ShouldBeErrorResponse(Resources.InvalidCredentials, Resources.InvalidCredentialsMessage);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_legal_agreement_is_not_accepted(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, new GaUser
            {
                Username = username,
                Password = PasswordManager.HashPassword(password),
                PasswordExpirationDate = DateTime.UtcNow.AddDays(1),
            });

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeErrorResponse(Resources.ClientLegalAgreementNotAccepted, Resources.LegalAgreementWarning);
        }

        [Theory, AutoData]
        public async Task return_bad_request_when_legal_agreement_is_not_accepted_and_client_is_prospect(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, new GaUser
            {
                Username = username,
                Password = PasswordManager.HashPassword(password),
                PasswordExpirationDate = DateTime.UtcNow.AddDays(1),
                RelationshipType = RelationshipType.Prospect,
            });

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeErrorResponse(Resources.ProspectLegalAgreementNotAccepted, Resources.LegalAgreementWarning);
        }

        [Theory, AutoData]
        public async Task return_token_when_user_is_valid(string username, string password)
        {
            tokenServer.SetFakeGaUser(username, CreateActiveGaUser(username, password));

            var response = await tokenServer.GetReponseByPasswordAsync(username, password);

            response.ShouldBeTokenResponse();
        }

        private static GaUser CreateActiveGaUser(string username, string password)
            => TokenServer.CreateActiveGaUser(username, password);
    }
}
